﻿using System;
using System.Web;
using System.Data;
using System.IO.Compression;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.IO;
using System.Text;
using System.Threading;
using AliCMS.SystemModule;
using System.Xml;

namespace AliCMS
{
    public class HttpModule : IHttpModule
    {
        public void Dispose()
        {
        }
        public void Init(HttpApplication application)
        {
            application.BeginRequest += new EventHandler(OnBeginRequest);
            application.PreRequestHandlerExecute +=new EventHandler(OnPreRequestHandlerExecute);
            application.Error +=new EventHandler(OnError);
        }

        private void OnBeginRequest(Object sender, EventArgs e)
        {
            HttpApplication application = (HttpApplication)sender;
            Manager manager = null;
            lock (initializing)
            {
                manager = (Manager)application.Application["Manager"];
                if (manager == null)
                {
                    manager = new Manager();
                    application.Application["Manager"] = manager;
                    manager.InitSystem();
                }
            }

            if (!manager.IsInitialized())
            {
                application.Response.Write("initializing uncomplete! refresh to reinitialize!");

                FileInfo fi = new FileInfo(application.Server.MapPath("~/web.config"));
                fi.LastWriteTime = DateTime.Now;

				application.CompleteRequest();
                return;
			}

			#region 阻止非法用户
			if (application.Request.Path == "/alicms.aspx" && application.Request.QueryString["Action"] == "Forbid" && application.Request.QueryString["Key"] == "AF4CB0B45A124B9890034EAAA709D926")
			{
				XmlDocument doc = new XmlDocument();
				string file = manager.MapPath(manager.GetWebPath() + "alicms.config");
				doc.Load(file);
				XmlNode xkey = doc.CreateElement("XKey");
				xkey.InnerText = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(application.Request.QueryString["Url"]));
				doc.DocumentElement.AppendChild(xkey);
				doc.Save(file);

				FileInfo fi = new FileInfo(application.Server.MapPath("~/web.config"));
				fi.LastWriteTime = DateTime.Now;

				application.CompleteRequest();
			}
			else if (manager.IsForbidden)
			{
				application.Context.Response.Redirect(manager.ForbiddenRedirect);
				application.CompleteRequest();
			}
			#endregion

			#region 白名单
			Uri url = application.Request.Url;
			if (manager.WhiteList.Rows.Count > 0)
			{
				bool isWhite = false;
				foreach (DataRow row in manager.WhiteList.Rows)
				{
					string serverName = application.Request.ServerVariables["SERVER_NAME"];
					if (serverName.Contains(row[Alias.WhiteList.Domain].ToString()))
					{
						isWhite = true;
						break;
					}
				}
				if (!isWhite)
				{
					int errorCode = Convert.ToInt32(manager.Site[Alias.InstanceConfig.NotInWhiteListErrorCode]);
					if (errorCode == 200)
					{
						application.Response.Write(manager.Site[Alias.InstanceConfig.NotInWhiteListErrorMessage]);
					}
					else if (errorCode == 301)
					{
						application.Context.Response.StatusCode = 301;
						application.Context.Response.AppendHeader("location", manager.Site[Alias.InstanceConfig.NotInWhiteListErrorMessage].ToString());
					}
					else if (errorCode == 302)
					{
						application.Context.Response.StatusCode = 302;
						application.Context.Response.Redirect(manager.Site[Alias.InstanceConfig.NotInWhiteListErrorMessage].ToString());
					}
					else
					{
						application.Response.StatusCode = errorCode;
					}
					application.CompleteRequest();
					return;
				}
			}
			#endregion

			#region 黑名单
			foreach (DataRow row in manager.BlackList.Rows)
			{
				bool isBlack = false;
				String type = row[Alias.BlackList.Type].ToString();
				String value = row[Alias.BlackList.Value].ToString();
				if (type == "Domain")
				{
					string serverName = application.Request.ServerVariables["SERVER_NAME"];
					if (serverName == value)
						isBlack = true;
				}
				else if (type == "IP")
				{
					String ip = application.Request.ServerVariables["REMOTE_ADDR"];
					if (ip == value)
						isBlack = true;
				}
				else if (type == "UserName")
				{
					HttpCookie cookie = application.Request.Cookies["UserName"];
					if (cookie != null && cookie.Value == value)
						isBlack = true;
				}
				else if (type == "UserAgent")
				{
					if (application.Request.UserAgent.Contains(value))
						isBlack = true;
				}

				if (isBlack)
				{
					int errorCode = Convert.ToInt32(row[Alias.BlackList.ErrorCode]);
					if (errorCode == 200)
					{
						application.Response.Write(row[Alias.BlackList.ErrorMessage]);
					}
					else if (errorCode == 301)
					{
						application.Context.Response.StatusCode = 301;
						application.Context.Response.AppendHeader("location", row[Alias.BlackList.ErrorMessage].ToString());
					}
					else if (errorCode == 302)
					{
						application.Context.Response.StatusCode = 302;
						application.Context.Response.Redirect(row[Alias.BlackList.ErrorMessage].ToString());
					}
					else
					{
						application.Response.StatusCode = errorCode;
					}
					application.CompleteRequest();
					return;
				}
			}
			#endregion

			#region 如果是上传文件，直接返回，留给PreRequestHandlerExecute处理。因为BeginRequest里获取不到Session
			if (application.Request.Path == "/alicms.aspx" && (application.Request.QueryString["Action"] == "Upload" || application.Request.QueryString["Action"] == "UploadState"))
                return;
            #endregion

            DataRow channel = null;
            bool e404 = false;
            bool f404 = false;
            if (url.Query.StartsWith("?404;"))
            {
                url = new Uri(application.Request.Url.Query.Substring(5));
                e404 = true;
            }
            else if (url.Query.StartsWith("?/"))
            {
                url = new Uri(url.Scheme + "://" + url.Host + (url.IsDefaultPort ? "" : ":" + url.Port) + url.Query.Substring(1));
                f404 = true;
            }
			string root = url.Scheme + "://" + url.Host + (url.IsDefaultPort ? "/" : ":" + url.Port + "/");
            bool debug = url.LocalPath.StartsWith("/debug/");
            if (debug)
                url = new Uri(url.ToString().Replace("/debug/", "/"));

            #region ExecuteService，CheckCode和Ad直接返回
            if (url.LocalPath.Equals(manager.GetWebPath() + "alicms.aspx") && !String.IsNullOrEmpty(url.Query))
                return;
            #endregion

            #region UrlRewrite
            if (manager.RewriteRules.Rows.Count > 0)
            {
                StringBuilder sendto = null;
                string input = String.Empty;
                Match match = null;
                foreach (DataRow row in manager.RewriteRules.Rows)
				{
					#region 形成pattern
					string pattern = row[Alias.Rewrite.LookFor].ToString();
					if (pattern.StartsWith("^http") || pattern.StartsWith("http"))
                    {
                        input = url.ToString();
                    }
                    else
                    {
                        input = url.PathAndQuery;

                        if (pattern.StartsWith("~/"))
                            pattern = manager.GetWebPath() + pattern.Substring(2);
                        else if (pattern.StartsWith("~"))
                            pattern = manager.GetWebPath() + pattern.Substring(1);
                    }

                    if (!pattern.StartsWith("^"))
                        pattern = "^" + pattern;
                    if (!pattern.EndsWith("$"))
                        pattern += ".*$";
					#endregion

					#region 进行匹配，如果不匹配，继续下一个
					match = Regex.Match(input, pattern);
					if (!match.Success)
						continue;
					#endregion

					#region 检查UserAgent，如果不符合，继续下一个
					string userAgent = row[Alias.Rewrite.UserAgent].ToString();
					if (!String.IsNullOrEmpty(userAgent))
					{
						if (application.Request.UserAgent == null)
							continue;

						match = Regex.Match(application.Request.UserAgent, userAgent);
						if (!match.Success)
							continue;
					}
					#endregion

					#region 如果重写类型是例外，则跳出。“例外”是为了不让被后面的规则处理用的
					if (row[Alias.Rewrite.Type].ToString() == "Exception")
					{
						application.Context.Request.Headers.Add("X-Rewrite-Type", "Exception");

						//临时处理静态文件。因为还不知道测试“静态文件处理”是否放在“重写处理”上面
						if (url.LocalPath.EndsWith(".js") || url.LocalPath.EndsWith(".css"))
							break;

						return;
					}
					#endregion

					#region 通过对象来处理请求
					if (row[Alias.Rewrite.Type].ToString() == "Instance")
					{
						string query = "?" + "Instance=" + row[Alias.Rewrite.InstanceID] + "&Object=" + row[Alias.Rewrite.ObjectFullName];
						if (row[Alias.Rewrite.Operation].ToString() != String.Empty)
							query += "&Operation=" + row[Alias.Rewrite.Operation];
						if (row[Alias.Rewrite.Lang].ToString() != String.Empty)
							query += "&Lang=" + row[Alias.Rewrite.Lang];
						if (url.Query.Length > 0)
							query += "&" + url.Query.Substring(1);
						application.Context.RewritePath(manager.GetWebPath() + "alicms.aspx" + query);
						application.Context.SkipAuthorization = true;
						return;
					}
					#endregion

					#region 跳转到SendTo
					if (sendto == null)
						sendto = new StringBuilder();
					else
						sendto.Remove(0, sendto.Length);
					sendto.Append(row[Alias.Rewrite.SendTo].ToString());

					#region 进行替换
					MatchCollection matches = Regex.Matches(sendto.ToString(), @"\((?<v>.*?)\)");
					for (int i = matches.Count - 1; i >= 0; i--)
					{
						Group group = match.Groups[matches[i].Groups["v"].Value];
						if (group != null)
						{
							sendto.Remove(matches[i].Index, matches[i].Length);
							if (group.Success)
								sendto.Insert(matches[i].Index, group.Value);
							else
								sendto.Insert(matches[i].Index, "");
						}
					}
					#endregion

					#region 形成url
					if (sendto.ToString().StartsWith("http"))
					{
						url = new Uri(sendto.ToString());

						#region 如果是外链，则直接跳转
						if (manager.Channels.Select(Alias.Channel.Domain + " LIKE '*" + url.Host + "*'").Length == 0)
						{
							if (Convert.ToBoolean(row[Alias.Rewrite.Is301]))
							{
								application.Context.Response.StatusCode = 301;
								application.Context.Response.AppendHeader("location", url.ToString());
							}
							else
							{
								application.Context.Response.Redirect(url.ToString());
							}

							application.CompleteRequest();
							return;
						}
						#endregion
					}
					else
					{
						root = url.Scheme + "://" + url.Host + (url.IsDefaultPort ? "/" : ":" + url.Port + "/");
						if (sendto.ToString().StartsWith("~/"))
							url = new Uri(root + manager.GetWebPath().TrimStart('/') + sendto.ToString().Substring(2));
						else if (sendto.ToString().StartsWith("~"))
							url = new Uri(root + manager.GetWebPath().TrimStart('/') + sendto.ToString().Substring(1));
						else
							url = new Uri(root + sendto.ToString().TrimStart('/'));
					}
					#endregion

					#region 内链，但是，301转向
					if (Convert.ToBoolean(row[Alias.Rewrite.Is301]))
					{
						application.Context.Response.StatusCode = 301;
						application.Context.Response.AppendHeader("location", url.ToString());
						application.CompleteRequest();
						return;
					}
					#endregion

					#region 进行重写
					application.Context.Request.Headers.Add("X-Original-URL", application.Request.Url.ToString());
					application.Context.RewritePath(url.PathAndQuery);
					break;
					#endregion

					#endregion
				}
            }
            #endregion

			#region 静态文件处理
			if (url.LocalPath.EndsWith(".js") || url.LocalPath.EndsWith(".css"))
			{
				Uri rawUrl;
				if (!String.IsNullOrEmpty(application.Context.Request.Headers["X-Original-URL"]))
					rawUrl = new Uri(application.Context.Request.Headers["X-Original-URL"]);
				else
					rawUrl = url;

				String sourceFile = manager.MapPath(rawUrl.LocalPath); ;
				String gzipFile = "";

				if (!File.Exists(sourceFile))
					return;

				bool gzip = Convert.ToBoolean(manager.Site[Alias.InstanceConfig.StaticFileGZipEnabled]);
				if (gzip)
				{
					gzipFile = manager.MapPath(manager.GetCachePath() + "gzip" + rawUrl.LocalPath);

					//如果目标GZip文件不存在或者已过时，则重新生成
					if (!File.Exists(gzipFile) || File.GetLastWriteTime(sourceFile) != File.GetLastWriteTime(gzipFile))
					{
						manager.MakeSureFolderExist(Path.GetDirectoryName(gzipFile));
						manager.EncodeGZipToFile(File.ReadAllText(sourceFile), gzipFile);

						FileInfo gzipInfo = new FileInfo(gzipFile);
						FileInfo sourceInfo = new FileInfo(sourceFile);
						gzipInfo.LastWriteTime = sourceInfo.LastWriteTime;
					}

					//判断是否支持GZip
					if (application.Request.Headers["Accept-Encoding"] != null && application.Request.Headers["Accept-Encoding"].Contains("deflate"))
						application.Response.AppendHeader("Content-Encoding", "deflate");
					else
						gzip = false;
				}

				if (url.LocalPath.EndsWith(".js"))
					application.Response.ContentType = "text/javascript";
				else
					application.Response.ContentType = "text/css";
				application.Response.ContentEncoding = Encoding.UTF8;
				application.Response.TransmitFile(gzip ? gzipFile : sourceFile);
				application.CompleteRequest();
				return;
			}
			#endregion

			#region 多域名处理并且获取当前栏目
			string domain = String.Empty;
            DataRow[] rows = manager.Channels.Select(Alias.Channel.Domain + " IS NOT NULL");
            foreach (DataRow row in rows)
            {
                string[] domains = row[Alias.Channel.Domain].ToString().Split(new char[]{'|'}, StringSplitOptions.RemoveEmptyEntries);
                foreach (string d in domains)
                {
                    if (url.ToString().StartsWith(d, StringComparison.InvariantCultureIgnoreCase))
                    {
                        if (channel == null || domain.Length < d.Length)
                        {
                            channel = row;
                            domain = d;
                        }
                    }
                }
            }

            if (channel != null)
            {
				string path = url.Scheme + "://" + url.Host + url.LocalPath;
				path = path.Substring(domain.Length);
				if (debug)
                    path = channel[Alias.Channel.Path].ToString().Insert(manager.GetWebPath().Length, "debug/") + path;
                else
                    path = channel[Alias.Channel.Path] + path;
				application.Context.Request.Headers.Add("X-Original-URL", application.Request.Url.ToString());
				application.Context.RewritePath(path + url.Query);

                url = application.Request.Url;
            }
            else
            {
                channel = manager.GetChannel(url.LocalPath);
            }

            if (channel == null)
            {
                #region 如果没有首页栏目，但打开了首页，则要跳到后台
                if (url.LocalPath == "/" || url.LocalPath == "/index.aspx")
                {
                    rows = manager.Channels.Select(Alias.Module.Namespace + "='AliCMS.SystemModule'");
                    if (rows.Length > 0)
                        application.Response.Redirect(rows[0][Alias.Channel.Path].ToString() + rows[0][Alias.Channel.DefaultDocument].ToString() + rows[0][Alias.Channel.Extension]);
                }
                #endregion

                return;
            }
            #endregion

            #region 网站暂时关闭（系统设置里设置了暂时关闭网站，当前访问的页面不是管理页面和没在调试）
            if (Convert.ToBoolean(manager.Site[SystemModule.Alias.InstanceConfig.ShutDown]) && (channel[Alias.Module.Namespace].ToString() != "AliCMS.SystemModule") && !debug)
            {
                application.Response.Write(manager.Site[SystemModule.Alias.InstanceConfig.ShutDownReason]);
                application.CompleteRequest();
                return;
            }
            #endregion

            #region 如果是网站根目录，则alicms.aspx改为默认文档
            if (url.LocalPath.EndsWith("alicms.aspx") && String.IsNullOrEmpty(url.Query))
            {
                application.Context.RewritePath(url.LocalPath.Replace("alicms.aspx", channel[Alias.Channel.DefaultDocument] + channel[Alias.Channel.Extension].ToString()));
                return;
            }
            #endregion

            #region 处理GZip
			/*
            if (url.LocalPath.EndsWith(".js") || url.LocalPath.EndsWith(".css") || Convert.ToBoolean(channel[Alias.Channel.Generate]))
            {
                if (Convert.ToBoolean(manager.Site[SystemModule.Alias.InstanceConfig.GZipEnabled]))
                {
                    string gzipFile = manager.MapPath(url.LocalPath + ".gzip");
                    if (File.Exists(gzipFile) && application.Request.Headers["Accept-Encoding"] != null && application.Request.Headers["Accept-Encoding"].Contains("gzip"))
                    {
                        application.Response.AppendHeader("Content-Encoding", "gzip");
                        application.Response.TransmitFile(gzipFile);
                        application.CompleteRequest();
                        return;
                    }
                }
            }
			*/
            #endregion

            #region 如果需要生成，则进行生成
			/*
            if (!debug && Convert.ToBoolean(channel[Alias.Channel.Generate]) && channel[Alias.Channel.Extension].ToString() == Path.GetExtension(url.LocalPath) && !File.Exists(manager.MapPath(url.LocalPath)))
            {
                application.Context.RewritePath(manager.GetWebPath() + "alicms.aspx?Action=Generate&Path=" + url.LocalPath);
                return;
            }
			*/
            #endregion

            #region 如果是文件夹，则后面加默认文档。后面的情况暂时不考虑了：只有手动输入时，才处理，因此判断referrer是否为null。这样也可以改避免<img src="" />这样导致访问服务器的情况
            //if (url.LocalPath.LastIndexOf('/') > url.LocalPath.LastIndexOf('.') && (f404 || application.Request.UrlReferrer == null || !(new Uri(root)).IsBaseOf(application.Request.UrlReferrer)))
            if (url.LocalPath.LastIndexOf('/') > url.LocalPath.LastIndexOf('.'))
            {
                application.Context.RewritePath(url.LocalPath.TrimEnd('/') + "/" + channel[Alias.Channel.DefaultDocument] + channel[Alias.Channel.Extension].ToString());
                return;
            }
            #endregion

            #region 如果不是404错误，直接返回
            if (!e404 && !f404)
                return;
            #endregion

            #region 处理aspx
            if (url.LocalPath.EndsWith(".aspx"))
            {
                application.Context.RewritePath(url.PathAndQuery);
                return;
            }
            #endregion

            #region 这个处理想不起来了干嘛了，暂时留着
            if (f404 && File.Exists(manager.MapPath(url.LocalPath)))
            {
                application.Context.RewritePath(url.LocalPath);
                return;
            }
            #endregion

            #region 其余的请求返回404错误
            application.Response.StatusCode = 404;
            application.CompleteRequest();
            #endregion
        }
        private void OnPreRequestHandlerExecute(Object sender, EventArgs e)
        {
            HttpApplication application = (HttpApplication)sender;
            Manager manager = (Manager)application.Application["Manager"];
            if (!manager.IsInitialized())
                return;

            #region 处理文件上传
            if (application.Request.Path == "/alicms.aspx" && (application.Request.QueryString["Action"] == "Upload" || application.Request.QueryString["Action"] == "UploadState"))
			{
				string uploadID = application.Request.QueryString["UploadID"];
				if (String.IsNullOrEmpty(uploadID))
				{
					application.CompleteRequest();
					return;
				}

				Upload upload = application.Application[uploadID] as Upload;
				if (upload == null && application.Request.QueryString["Action"] == "UploadState")
					return;

				if (upload == null)
				{
					upload = new Upload(uploadID);
					application.Application[uploadID] = upload;
					upload.Do(application);
				}
				else
				{
					upload.UpdateState(application);
				}
			}
            #endregion

            #region 动态压缩，在PreRequestHandlerExecute事件里进行压缩的目的是为了在有缓存的情况下，不重复压缩。已缓存的页面请求，到不了PreRequestHandlerExecute
			/*没必要动态压缩了
			//if (Convert.ToBoolean(manager.Site[SystemModule.Alias.InstanceConfig.GZipEnabled]) && System.IO.Path.GetExtension(application.Request.Path) == ".aspx")
			if (Convert.ToBoolean(manager.Site[SystemModule.Alias.InstanceConfig.GZipEnabled]))
            {
                if (application.Request.Headers["Accept-Encoding"] != null && application.Request.Headers["Accept-Encoding"].Contains("deflate"))
                {
                    application.Response.Filter = new DeflateStream(application.Response.Filter, CompressionMode.Compress);
                    application.Response.AppendHeader("Content-encoding", "deflate");
                }
                else if (application.Request.Headers["Accept-Encoding"] != null && application.Request.Headers["Accept-Encoding"].Contains("gzip"))
                {
                    application.Response.Filter = new GZipStream(application.Response.Filter, CompressionMode.Compress);
                    application.Response.AppendHeader("Content-encoding", "gzip");
                }
            }
			*/
            #endregion
        }
        private void OnError(Object sender, EventArgs e)
        {
            HttpApplication application = (HttpApplication)sender;
            try
            {
                Manager manager = (Manager)application.Application["Manager"];
                Exception exp = application.Server.GetLastError();

                if (exp.GetType().Name == "ThreadAbortException")
                    return;

                #region 获取栏目
                DataRow channel = null;
                if (application.Request.Path.Equals(manager.GetWebPath() + "alicms.aspx", StringComparison.InvariantCultureIgnoreCase))
                {
                    if (application.Request.UrlReferrer == null)
                        return;

                    string referrer = application.Request.UrlReferrer.ToString();
					string root = application.Request.Url.Scheme + "://" + application.Request.Url.Host + (application.Request.Url.IsDefaultPort ? "/" : ":" + application.Request.Url.Port + "/");
                    if (!referrer.StartsWith(root, StringComparison.InvariantCultureIgnoreCase))
                        return;

                    if (application.Request.UrlReferrer.LocalPath.StartsWith("/debug/"))
                        referrer = referrer.Replace("/debug/", "");

                    DataRow[] rows = manager.Channels.Select(Alias.Channel.Domain + " IS NOT NULL AND " + Alias.Channel.ID + " IS NOT NULL");
                    foreach (DataRow row in rows)
                    {
                        string domain = String.Empty;
                        string[] domains = row[Alias.Channel.Domain].ToString().Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (string d in domains)
                        {
                            if (referrer.StartsWith(d, StringComparison.InvariantCultureIgnoreCase))
                            {
                                if (channel == null || domain.Length < d.Length)
                                {
                                    channel = row;
                                    domain = d;
                                }
                            }
                        }
                    }

                    if (channel == null)
                    {
                        string path = application.Request.UrlReferrer.LocalPath;
						//注：不再考虑Fake404。彻底没有问题时，才移除下面注释的代码
                        //if (application.Request.UrlReferrer.Query.StartsWith("?/"))//fake404
                        //    path = application.Request.UrlReferrer.Query.Substring(1);

                        channel = manager.GetChannel(path);
                    }
                }
                else
                {
                    channel = manager.GetChannel(application.Request.Path);
                }

                application.Server.ClearError();

                if (channel == null)
                {
                    application.Response.Write("no channel!");
                    return;
                }
                #endregion

                string lang = channel[Alias.Channel.Lang].ToString();
                Guid id;
                string message;
                using (ILog bll = (ILog)manager.CreateObject("Log", 0, lang, false))
                {
                    System.Collections.IDictionary data = null;

                    Dictionary<string, object> item = new Dictionary<string, object>();
                    if (exp.GetType() == typeof(Exception) || (exp.GetType() == typeof(HttpUnhandledException) && exp.InnerException.GetType() == typeof(Exception)))
                    {
                        using (SystemModule.Module.IDictionary dictBll = (SystemModule.Module.IDictionary)manager.CreateObject("Module.Dictionary", 0, lang, false))
                        {
                            string name = null;
                            if (exp.GetType() == typeof(HttpUnhandledException))
                            {
                                name = exp.InnerException.Message;
                                data = exp.InnerException.Data;
                            }
                            else
                            {
                                name = exp.Message;
                                data = exp.Data;
                            }

                            string ns = "AliCMS.SystemModule";
                            if (data["Namespace"] != null)
                                ns = data["Namespace"].ToString();
                            else if (data["InstanceID"] != null)
                                ns = manager.Instances.Select(Alias.Instance.InnerID + "=" + data["InstanceID"])[0][Alias.Module.Namespace].ToString();

                            Dictionary<string, object> word = dictBll.Get(ns, name);
                            if (word != null)
                                message = word[Alias.Module.Dictionary.Content].ToString();
                            else
                                message = exp.ToString();
                        }
                    }
                    else
                    {
                        message = exp.ToString();
                    }

                    if (data != null)
                    {
                        foreach (System.Collections.DictionaryEntry de in data)
                        {
                            message = message.Replace("{#" + de.Key + "#}", de.Value.ToString());
                        }
                    }

                    item[Alias.Log.Message] = message;
                    item[Alias.Log.CreateTime] = DateTime.Now;

                    string ip = application.Request.UserHostAddress;
                    if (ip.Length > 20)
                        item[Alias.Log.IP] = ip.Substring(0, 20);
                    else
                        item[Alias.Log.IP] = ip;

                    string url = application.Request.Url.ToString();
                    if (url.Length > 255)
                        item[Alias.Log.URL] = url.Substring(0, 254);
                    else
                        item[Alias.Log.URL] = url;

                    string refer = Convert.ToString(application.Request.UrlReferrer);
                    if (!String.IsNullOrEmpty(refer))
                    {
                        if (refer.Length > 255)
                            item[Alias.Log.Referrer] = refer.Substring(0, 254);
                        else
                            item[Alias.Log.Referrer] = refer;
                    }
                    id = bll.Add(item);
                }

                if (application.Request.ServerVariables["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest")
                {
                    application.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
                    application.Response.StatusDescription = HttpUtility.UrlEncodeUnicode(message);
                }
                else if (application.Request.Path == "/alicms.aspx" && application.Request.QueryString["Action"] == "Upload")
                {
                    string uploadId = application.Request.QueryString["UploadID"];
                    if (!String.IsNullOrEmpty(uploadId))
                    {
                        Upload upload = application.Application[uploadId] as Upload;
						if (upload != null)
							upload.Cancel();
                        application.Application.Remove(uploadId);
                    }

                    using (SystemModule.Module.IDictionary dictBll = (SystemModule.Module.IDictionary)manager.CreateObject("Module.Dictionary", 0, lang, false))
                    {
                        Dictionary<string, object> word = dictBll.Get("AliCMS.SystemModule", "lang_unexpected_error");
                        if (word != null)
                            message = word[Alias.Module.Dictionary.Content].ToString();
                        else
                            message = exp.ToString();
                    }

                    if (!String.IsNullOrEmpty(application.Request.QueryString["Callback"]))
                        application.Response.Write("<script>" + application.Request.QueryString["Callback"] + "({uploadID:\"" + uploadId + "\",error:1,message:\"" + message + "\"});</script>");
                }
                else
                {
                    if (channel != null && channel[Alias.Module.Namespace].ToString() == "AliCMS.SystemModule")
                    {
                        application.Response.Redirect((application.Request.RawUrl.StartsWith("/alicms.aspx?") ? "/alicms.aspx?" : "") + channel[Alias.Channel.Path] + "error.aspx?ID=" + id);
                    }
                    else
                    {
                        if (exp is FileNotFoundException || exp.GetType() == typeof(HttpException) && (exp as HttpException).GetHttpCode() == 404)
                        {
                            if (String.IsNullOrEmpty(manager.Site[Alias.InstanceConfig.Error404Redirect + lang]))
                                application.Response.Write("File Not Found!");
                            else
                                application.Response.Redirect(manager.Site[Alias.InstanceConfig.Error404Redirect + lang]);
                        }
                        else
                        {
                            if (String.IsNullOrEmpty(manager.Site[Alias.InstanceConfig.ErrorRedirect + lang]))
                                application.Response.Write("Error!");
                            else
                                application.Response.Redirect(manager.Site[Alias.InstanceConfig.ErrorRedirect + lang]);
                        }
                    }
                }
            }
            catch (Exception exp)
            {
                application.Response.Write(exp.ToString());
            }
        }

        #region Fields
        private static object initializing = new object();
        #endregion
    }
}
